package com.csx.base.design.constructor.singleton;

/**
 * 单例的经典五种写法
 * <p> ① 饿汉式
 * <p> ② 懒汉式
 * <p> ③ 懒汉式（双重校验版）
 * <p> ④ 静态内部类
 * <p> ⑤ 枚举
 *
 * @author cuisongxu
 * @date 2023/3/27 18:44
 */
public class Singleton {

    /**
     * 方式一: 饿汉式
     */
    static class SingletonE {

        private static final SingletonE instance = new SingletonE();

        private SingletonE() {}

        public static SingletonE getInstance() {
            return instance;
        }
    }

    /**
     * 方式二: 懒汉式
     */
    static class SingletonLan {

        private static volatile SingletonLan instance = null;

        private SingletonLan() {}

        public static synchronized SingletonLan getInstance() {
            if(instance == null) {
                instance = new SingletonLan();
                return instance;
            }
            return instance;
        }
    }

    /**
     * 方式三: 懒汉式双重校验(解决懒汉式获取实例并发度低的问题)
     */
    static class DoubleCheckSingleton {

        private static volatile DoubleCheckSingleton instance = null;

        private DoubleCheckSingleton() {}

        /**
         * 细节点： 这里通过 localRef 来将原本 2次(第一次是判断 instance==null, 第二次是 return instance)的volatile变量使用 变为1次(只有一次 temp = instance)
         *      访问 volatile 修饰的变量需要访问主存，而非volatile修饰的变量只需要访问 寄存。
         * @return
         */
        public static DoubleCheckSingleton getInstance() {
            DoubleCheckSingleton temp = instance;
            if(temp == null) {
                synchronized (DoubleCheckSingleton.class) {
                    temp = instance;
                    if(temp == null) {
                        temp = new DoubleCheckSingleton();
                        instance = temp;
                    }
                }
            }
            return temp;
        }
    }

    /**
     * 方式四: 静态内部类
     *  相对于 饿汉式的区别在于:
     *      静态内部类不会在外部类加载时立即加载内部类,从而是的 内部类中的单例对象并不是立即被创建出来,只有在 第一次调用 getInstance 时才会触发内部类
     *      加载从而创建单例对象。因此相对于 普通的饿汉式，其具有延迟加载的效果。
     */
    static class StaticInnerClassSingleton {

        private StaticInnerClassSingleton() {}

        static class SingletonHolder {

            private static final StaticInnerClassSingleton instance = new StaticInnerClassSingleton();

            public static StaticInnerClassSingleton getInstance() {
                return SingletonHolder.instance;
            }
        }
    }

    /**
     * 方式五: 枚举
     */
    enum EnumSingleton {

        /**
         * 单例对象
         */
        INSTANCE;

    }
}
